掌握 C++ 对象生命周期的关键,在于掌控其在 堆和栈中的存在机制。拷贝控制定义了类如何管理其 生命周期 通过两种操作实现:即 拷贝构造函数 和 拷贝赋值操作符。
1. 初始化与赋值的区别
直接初始化(例如, string dots(10, '.'))会直接调用构造函数。然而, 拷贝初始化 (string s2 = dots)依赖于拷贝构造函数。与初始化不同, 赋值 (trans = accum)会使用 operator=来覆盖一个已存在的对象。一个关键限制是:拷贝构造函数的参数必须是引用(const Foo&);否则,按值传递参数将引发一个 无限递归循环 拷贝调用的循环。
2. 合成的作用
如果你没有定义这些成员,编译器会提供 合成的 版本,执行逐成员拷贝。请注意:虽然对简单类型足够,但对管理动态内存的类来说常常失效,可能导致悬空指针或重复释放。
main.py
TERMINALbash — 80x24
> Ready. Click "Run" to execute.
>
QUESTION 1
Why must the first parameter of a copy constructor be a reference type (usually const)?
To allow the compiler to optimize the code into a move operation.
To prevent infinite recursion during parameter initialization.
Because pointers are not allowed in constructor signatures.
To ensure the object is placed on the heap rather than the stack.
✅ Correct!
Correct! If the parameter were passed by value, calling the copy constructor would require a copy of the argument, which would call the copy constructor again, infinitely.❌ Incorrect
Think about how arguments are passed. Passing by value requires a copy... and how is that copy made?QUESTION 2
What is the primary difference between Copy Initialization and Direct Initialization?
Direct initialization uses the assignment operator; copy initialization does not.
Copy initialization always requires the 'new' keyword.
Direct initialization asks the compiler to find the best constructor; copy initialization requires the copy constructor.
There is no functional difference; they are just different syntax for the same call.
✅ Correct!
Exactly. Copy initialization happens when using '=', passing by value, or returning by value, and specifically requires the copy/move constructor.❌ Incorrect
Direct initialization (using parens or braces) matches against all available constructors, while copy initialization specifically invokes the copy constructor.QUESTION 3
Assume 'numbered' has a synthesized copy constructor that copies a unique ID 'mysn'. What happens if you run: numbered a, b = a, c = b;?
Each object (a, b, c) will have a unique 'mysn' value.
The program will fail to compile because IDs cannot be copied.
All three objects will share the exact same 'mysn' value.
Object 'a' will be reset to zero after the copy.
✅ Correct!
Since the synthesized version performs memberwise copy, it simply duplicates the value of 'mysn' from the source, defeating the uniqueness.❌ Incorrect
The synthesized copy constructor does not 'know' that 'mysn' is supposed to be unique; it just copies the bits.QUESTION 4
Which of the following would trigger a compilation error if the constructor 'vector<int>(int size)' is marked 'explicit'?
vector<int> v(10);vector<int> v = 10;f(vector<int>(10));vector<int>* p = new vector<int>(10);✅ Correct!
Correct! 'explicit' prevents the use of a constructor in copy-initialization contexts (like using '=').❌ Incorrect
Explicit constructors can be used for direct initialization but not for implicit conversions or copy initialization using '='.QUESTION 5
What should a well-behaved copy-assignment operator usually return?
void
A copy of the current object by value.
A reference to the left-hand operand (*this).
The memory address of the right-hand operand.
✅ Correct!
This is a best practice to remain consistent with built-in types and allow assignment chaining (e.g., a = b = c).❌ Incorrect
To allow chaining and maintain standard C++ behavior, return a reference to the modified object.Case Study: Identifying Copy Logistics
Trace object construction and assignment
Analyze the following snippet:
Point global;
Point foo_bar(Point arg) {
Point local = arg;
Point *heap = new Point(global);
*heap = local;
Point pa[2] = { local, *heap };
return *heap;
}
Q
1. How many times is the copy constructor called in the execution of foo_bar?
Solution:
The copy constructor is called 6 times: 1. Passing 'arg' by value. 2. Initializing 'local'. 3. Dynamic construction of '*heap' from 'global'. 4. Initializing pa[0]. 5. Initializing pa[1]. 6. Initializing the return value from '*heap'.
The copy constructor is called 6 times: 1. Passing 'arg' by value. 2. Initializing 'local'. 3. Dynamic construction of '*heap' from 'global'. 4. Initializing pa[0]. 5. Initializing pa[1]. 6. Initializing the return value from '*heap'.
Q
2. Does the line '*heap = local' use the copy constructor?
Solution:
No. This is an assignment operation on an already existing object pointed to by 'heap'. It uses the copy-assignment operator (
No. This is an assignment operation on an already existing object pointed to by 'heap'. It uses the copy-assignment operator (
operator=), not the copy constructor.Q
3. If the 'Message' class used synthesized copy control while managing a list of 'Folders', what potential danger arises?
Solution:
A 'shallow copy' would occur. The new 'Message' would point to the same internal resources as the old one, but the 'Folders' wouldn't know about the new message. This leads to broken links or double-free errors when the messages are destroyed.
A 'shallow copy' would occur. The new 'Message' would point to the same internal resources as the old one, but the 'Folders' wouldn't know about the new message. This leads to broken links or double-free errors when the messages are destroyed.